<?php

namespace App\Http\Services;

use App\Http\Repositories\Daos\Order\OrderDao;
use App\Http\Requests\UserContext;
use App\Http\Traits\Errors;
use App\Models\ClusterMember;
use App\Models\Drag;
use App\Models\DragDetail;
use App\Models\DragonView;
use App\Models\Order;
use App\Models\OrderDetail;
use App\Models\RefundOrder;
use App\Util\Helper;
use App\Util\WechatPay\WechatPayUtil;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class OrderService extends BaseService
{
    use Errors;

    protected $orderDao;

    public function __construct(OrderDao $orderDao)
    {
        $this->orderDao = $orderDao;
    }

    public function lists(UserContext $userContext)
    {
        $userId    = $userContext->getId();
        $isAttempt = request('is_attempt') ?? 0;//我参与
        $verify    = request('to_verify') ?? 0;//待核销
        $isNormal  = request('is_normal') ?? 0;//接龙详情中的接龙列表（已取消不显示）
        $dragonId  = request('dragon_id') ?? 0;
        $condition = [
            'dragon_id'  => $dragonId,
            'pay_status' => 1
        ];

        $page   = request('page') ?? 1;
        $size   = request('size') ?? 10;
        $field  = ['id', 'dragon_id', 'user_id', 'dragon_serial', 'total_num', 'created_at', 'goods_snap', 'pay_total', 'price_real', 'status', 'verify', 'remark'];
        $offset = ($page * $size) - $size;
        $query  = $this->orderDao->getModel()->where($condition)->with(["userInfo" => function ($q) {
            $q->select(['id', 'nickname', 'avatar']);
        }, "dragonInfo"                                                            => function ($q) {
            $q->select(['id', 'user_id', 'cluster_id']);
        }]);
        if ($isAttempt) {
            $query->where('user_id', $userId);
        }
        if ($verify) {
            $query->where('verify', 1)->where('status', 0)->where('refund_status', 0);
        }
        if ($isNormal) {
            $query->where('status', 0);
        }
        $totalQuery = clone $query;
        $list       = $query->orderBy('id', 'desc')->limit($size)->offset($offset)->get($field);
        if (!empty($list)) {
            foreach ($list as &$item) {
                $item['time_str'] = Helper::pastTime($item['created_at']);
                $item['can_op']   = 0;
                //核销权限检测
                if ($item['dragonInfo']['user_id'] == $userId) {//当前接龙就是当前用户发的
                    $item['can_op'] = 1;
                    continue;
                }
                if ($item['dragonInfo']['cluster_id'] != 0) {//该接龙设置了群组，则群主和管理员皆可核销
                    $item['can_op'] = ClusterMember::checkOpStatus($item['dragonInfo']['cluster_id'], $userId);
                }

            }
            unset($item);
        }
        $total = $totalQuery->count();
        return compact("list", "total");
    }

    public function createOrder(UserContext $userContext)
    {
        $userId   = $userContext->getId();
        $dragInfo = request('drag_info') ?? '';
        if (empty($dragInfo)) $this->showError('请选择接龙的商品');
        if (empty($dragInfo['goods_list'])) $this->showError('接龙异常');
        $dragon = Drag::where('id', $dragInfo['id'])->first();
        if (empty($dragon)) $this->showError('接龙不存在');
        if ($dragon['status'] == 0 || $dragon['purchase_status'] == 1) $this->showError('接龙已结束');
        if (time() < strtotime($dragon['start_time'])) $this->showError('接龙还未开始');
        if (time() > strtotime($dragon['end_time'])) $this->showError('接龙已结束');
        $orderSn    = Helper::sn(20);
        $priceTotal = 0;
        $numTotal   = 0;
        $goodsList  = self::dealGoods($dragInfo['goods_list']);
        foreach ($goodsList as $item) {
            $priceTotal += $item['num'] * $item['price'] * 100;
            $numTotal   += $item['num'];
        }
        if (empty($numTotal)) $this->showError('请选择接龙的商品');
        $orderData = [
            'order_sn'   => $orderSn,
            'user_id'    => $userId,
            'dragon_id'  => $dragInfo['id'],
            'price_real' => $priceTotal,
            'total_num'  => $numTotal,
            'pay_total'  => $priceTotal,
            'status'     => 0,
            'remark'     => $dragInfo['remark'] ?? '',
            'goods_snap' => $goodsList,
            'pay_type'   => 'wechat_mini'
        ];
        DB::beginTransaction();
        try {
            //库存操作
            foreach ($goodsList as $item) {
                $res = DragDetail::where('id', $item['id'])->where('valid', 1)->where('store', '>=', $item['num'])->decrement('store', $item['num']);
                if (!$res) $this->showError('库存异常，接龙失败');
            }
            //创建订单
            $order = $this->orderDao->save($orderData);
            //订单详情
            $orderDetailData = [];
            foreach ($goodsList as $item) {
                $data['order_id']         = $order->id;
                $data['dragon_id']        = $dragInfo['id'];
                $data['user_id']          = $userId;
                $data['dragon_detail_id'] = $item['id'];
                $data['price']            = $item['price'];
                $data['num']              = $item['num'];
                $data['created_at']       = time();
                $data['updated_at']       = time();
                $orderDetailData[]        = $data;
            }
            if (!empty($orderDetailData)) {
                DB::table('order_detail')->insert($orderDetailData);
            }
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error('接龙失败:' . $exception->getMessage());
            $this->showError($exception->getMessage());
        }
        return [
            'order_sn' => $orderSn,
            'id'       => $order['id']
        ];
    }


    public function serial($dragonId = 0, $pageSize = 3)
    {
        if (empty($dragonId)) {
            $dragonId = request('dragon_id') ?? 0;
        }
        $condition = [
            'dragon_id'     => $dragonId,
            'pay_status'    => 1,
            'status'        => 0,
            'refund_status' => 0
        ];
        $page      = 1;
        $size      = $pageSize;
        $field     = ['id', 'dragon_id', 'user_id', 'dragon_serial', 'total_num', 'created_at', 'goods_snap', 'pay_total', 'status', 'verify', 'remark'];
        $offset    = ($page * $size) - $size;
        $query     = $this->orderDao->getModel()->where($condition)->with(["userInfo" => function ($q) {
            $q->select(['id', 'nickname', 'avatar']);
        }, "dragonInfo"                                                               => function ($q) {
            $q->select(['id', 'user_id', 'cluster_id']);
        }]);

        $list = $query->orderBy('id', 'desc')->limit($size)->offset($offset)->get($field);
        if (!empty($list)) {
            foreach ($list as &$item) {
                $item['time_str'] = Helper::pastTime($item['created_at']);
                $nickname         = $item->userInfo->nickname;
                $item->nickname   = mb_substr($nickname, 0, 1) . '**';
                foreach ($item['goods_snap'] as $value) {
                    $item['first_title'] = $value['title'];
                    break;
                }
            }
            unset($item);
        }
        return $list;
    }

    public function statics(UserContext $userContext)
    {
        $userId               = $userContext->getId();
        $begin                = strtotime(date('Y-m-d') . ' 00:00:00');
        $end                  = strtotime(date('Y-m-d') . ' 23:59:59');
        $statics              = $this->orderDao->getModel()->where('pay_status', 1)->where('status', 0)
            ->where('created_at', '>=', $begin)->where('created_at', '<=', $end)
            ->whereIn('dragon_id', function ($q) use ($userId) {
                $q->where('user_id', $userId)->select('id')->from('dragon');
            })->select(DB::raw("count(*) as total_num,COALESCE(SUM(pay_total),0.00) AS total_price"))->first();
        $statics->total_price = sprintf("%.2f", ($statics->total_price) / 100);
        return compact("statics");
    }

    public function createRefundOrder(UserContext $userContext)
    {
        $userId       = $userContext->getId();
        $orderId      = request('oid') ?? 0;
        $refundReason = request('reason') ?? '';
        $order        = $this->orderDao->getOne(['user_id' => $userId, 'id' => $orderId]);
        if (empty($order)) $this->showError('接龙订单不存在');
        if ($order['status'] == -1 || $order['pay_status'] != 1 || $order['verify'] == 2 || $order['refund_status'] != 0) $this->showError('当前接龙订单状态不可取消');
        DB::beginTransaction();
        try {
            $tkOrderSn = 'TK' . Helper::randString(18, 1);
            $data      = [
                'th_order_sn' => $tkOrderSn,
                'order_id'    => $orderId,
                'reason'      => $refundReason,
                'channel'     => '原路退回'
            ];
            switch ($order['pay_type']) {
                case 'wechat_mini':
                    $data['status'] = 1;
                    $rel            = $this->orderDao->getModel()->where('id', $orderId)->where('status', 0)->where('pay_status', 1)->where('refund_status', 0)->update(['refund_status' => 1]);//用此种方式防止更新的时候状态通过了上面判断但却发生了其他状态变化
                    if (!$rel) $this->showError('取消接龙订单失败');
                    (new WechatPayUtil())->refundOrder($order, $tkOrderSn);
                    break;
                default:
                    break;
            }
            RefundOrder::create($data);
            $order->refund_status = 1;
            $order->save();
            DB::commit();
        } catch (\Exception $exception) {
            DB::rollBack();
            Log::error('取消订单失败,订单号' . $orderId . '原因' . $exception->getMessage());
            $this->showError('取消接龙订单失败');
        }
        return true;
    }

    public function verifyOrder(UserContext $userContext)
    {
        $userId  = $userContext->getId();
        $orderId = request('oid') ?? 0;
        if (empty($orderId)) $this->showError('请选择核销订单');
        $orderInfo = $this->orderDao->getOne(['id' => $orderId]);
        if (empty($orderInfo)) $this->showError('要核销的订单不存在');
        if ($orderInfo['status'] == -1 || $orderInfo['refund_status'] != 0) $this->showError('订单状态异常');
        if ($orderInfo['pay_status'] != 1) $this->showError('订单未付款');
        if ($orderInfo['verify'] != 1) $this->showError('该订单已核销');
        $dragonInfo = Drag::where('id', $orderInfo['dragon_id'])->first();
        //核销权限检测
        $flag = false;
        if ($dragonInfo['user_id'] == $userId) {//当前接龙就是当前用户发的
            $flag = true;
        }
        if ($dragonInfo['cluster_id'] != 0) {//该接龙设置了群组，则群主和管理员皆可核销
            $flag = ClusterMember::checkOpStatus($dragonInfo['cluster_id'], $userId);
        }
        if (!$flag) $this->showError('没有核销权限');
        $orderInfo->verify    = 2;
        $orderInfo->verify_at = time();
        $orderInfo->save();
        return true;
    }

    public function singleDragonStatics()
    {
        $dragonId = request('dragon_id') ?? 0;
        if (empty($dragonId)) $this->showError('接龙不存在');
        $sql                      = "COALESCE(SUM(CASE WHEN status = 0 AND pay_status = 1 AND refund_status = 0 THEN price_real ELSE 0 END), 0) AS total_price,
                       COALESCE(SUM(CASE WHEN status = -1 AND pay_status = 1 THEN price_real ELSE 0 END), 0) AS cancel_price,
                       COALESCE(SUM(CASE WHEN status = 0 AND pay_status = 1 AND refund_status = 0 AND verify = 1 THEN price_real ELSE 0 END), 0) AS no_verify_price,
                       COALESCE(SUM(CASE WHEN status = 0 AND pay_status = 1 AND refund_status = 0 AND verify = 2 THEN price_real ELSE 0 END), 0) AS verify_price,
                       SUM(CASE WHEN status = 0 AND pay_status = 1 AND refund_status = 0 THEN 1 ELSE 0 END) AS total_order,
                       COALESCE(SUM(CASE WHEN status = 0 AND pay_status = 1 AND refund_status = 0 THEN total_num ELSE 0 END), 0) AS total_num,
                       COUNT(DISTINCT CASE WHEN status = 0 AND pay_status = 1 AND refund_status = 0 THEN user_id ELSE NULL END) AS total_person";
        $statics                  = DB::table('order')->selectRaw($sql)
            ->where('dragon_id', $dragonId)
            ->first();
        $statics->total_price     = sprintf("%.2f", $statics->total_price / 100);
        $statics->cancel_price    = sprintf("%.2f", $statics->cancel_price / 100);
        $statics->no_verify_price = sprintf("%.2f", $statics->no_verify_price / 100);
        $statics->verify_price    = sprintf("%.2f", $statics->verify_price / 100);
        $goodsList                = OrderDetail::where('dragon_id', $dragonId)->selectRaw("
        COALESCE(SUM(CASE WHEN price THEN price*num ELSE 0 END), 0) AS price,
        COALESCE(SUM(CASE WHEN num THEN num ELSE 0 END), 0) AS num,
        dragon_detail_id
        ")->groupBy('dragon_detail_id')->with(["goodsInfo" => function ($q) {
            $q->select(['id', 'title']);
        }])->get()->toArray();
        $statics->browse          = DragonView::where('dragon_id', $dragonId)->count();
        return compact("statics", "goodsList");
    }

    public function totalStatics(UserContext $userContext)
    {
        $userId    = $userContext->getId();
        $type      = request('type') ?? 1;
        $startTime = strtotime(date('Y-m-d 00:00:00'));
        $endTime   = strtotime(date('Y-m-d H:i:s'));
        $days      = 1;
        if ($type == 2) {
            $startTime = strtotime(request('start') ?? 0);
            $endTime   = strtotime(request('end') . ' 23:59:59' ?? 0);
            $days      = (int)floor((abs($endTime - $startTime) / (3600 * 24))) + 1;
        }
        $sql              = "COUNT(CASE WHEN pay_status = 1  THEN 1 ELSE 0 END) AS ddzs,
               COALESCE(SUM(CASE WHEN  pay_status = 1  THEN price_real ELSE 0 END), 0) AS ddzje,
               SUM(CASE WHEN pay_status = 1 and order.status =0 and refund_status=0  THEN 1 ELSE 0 END) AS yxddzs,
               COALESCE(SUM(CASE WHEN  pay_status = 1 and  order.status =0 and refund_status=0 THEN price_real ELSE 0 END), 0) AS yxddzje,
               SUM(CASE WHEN  pay_status = 1 and  order.status =-1 and refund_status=2 THEN 1 ELSE 0 END) AS yqxdds,
               COALESCE(SUM(CASE WHEN  pay_status = 1 and  order.status =0 and refund_status=0 and verify =2 THEN price_real ELSE 0 END), 0) AS yhxje,
               COALESCE(SUM(CASE WHEN  pay_status = 1 and  order.status =0 and refund_status=0 and verify =1 THEN price_real ELSE 0 END), 0) AS whxje,
               COALESCE(SUM(CASE WHEN  pay_status = 1 and  order.status =-1 and refund_status=2  THEN price_real ELSE 0 END), 0) AS yqxje,
               COUNT(DISTINCT CASE WHEN order.status = 0 AND pay_status = 1 AND refund_status = 0 THEN order.user_id ELSE NULL END) AS yxjlzrs";
        $statics          = DB::table('order')->leftJoin('dragon', 'dragon.id', '=', 'order.dragon_id')->selectRaw($sql)
            ->where('order.created_at', '>=', $startTime)->where('order.created_at', '<=', $endTime)->where('dragon.user_id', $userId)
            ->first();
        $statics->kdj     = !empty($statics->yxjlzrs) ? sprintf("%.2f", $statics->yxddzje / $statics->yxjlzrs) : 0;
        $statics->fwzs    = DragonView::where('created_at', '>=', $startTime)->where('created_at', '<=', $endTime)->count();
        $statics->ddzje   = sprintf("%.2f", $statics->ddzje / 100);
        $statics->yxddzje = sprintf("%.2f", $statics->yxddzje / 100);
        $statics->yhxje   = sprintf("%.2f", $statics->yhxje / 100);
        $statics->whxje   = sprintf("%.2f", $statics->whxje / 100);
        $statics->yqxje   = sprintf("%.2f", $statics->yqxje / 100);
        $statics->kdj     = sprintf("%.2f", $statics->kdj / 100);
        $statics->zhl     = !empty($statics->fwzs) ? sprintf("%.2f", ($statics->yxjlzrs / $statics->fwzs) * 100) : 0;
        $dragonList1      = Order::where('created_at', '>=', $startTime)->where('created_at', '<=', $endTime)
            ->where('pay_status', 1)->where('status', 0)->where('refund_status', 0)
            ->selectRaw("sum(price_real) as price,dragon_id")->whereIn('dragon_id', function ($q) use ($userId) {
                $q->where('user_id', $userId)->select('id')->from('dragon');
            })
            ->groupBy('dragon_id')->with(["dragonInfo" => function ($q) {
                $q->select(['id', 'title']);
            }])->having('price', '>', 0)->limit(5)->offset(0)->orderBy('price', 'desc')->get()->toArray();
        $dragonList2      = Order::where('created_at', '>=', $startTime)->where('created_at', '<=', $endTime)
            ->where('pay_status', 1)->where('status', 0)->where('refund_status', 0)->whereIn('dragon_id', function ($q) use ($userId) {
                $q->where('user_id', $userId)->select('id')->from('dragon');
            })
            ->selectRaw("COUNT(*) AS total, dragon_id")
            ->groupBy('dragon_id')->with(["dragonInfo" => function ($q) {
                $q->select(['id', 'title']);
            }])->limit(5)->offset(0)->orderBy('total', 'desc')->get()->toArray();
        if (!empty($dragonList1)) {
            foreach ($dragonList1 as &$item) {
                $item['price'] = sprintf("%.2f", $item['price'] / 100);
            }
            unset($item);
        }
        $chartList = self::createChart($type, $userId, $days, $startTime, $endTime);
        return compact("statics", "dragonList1", "dragonList2", "chartList");
    }

    protected static function createChart($type = 1, $userId, $days, $startTime, $endTime)
    {
//        $sql = "SUM(CASE WHEN pay_status = 1 and status =0 and refund_status=0  THEN 1 ELSE 0 END) AS order_num,
//                    COALESCE(SUM(CASE WHEN  pay_status = 1 and  status =0 and refund_status=0 THEN price_real ELSE 0 END), 0) AS pay_total";
        $sql = "COALESCE(SUM(CASE WHEN  pay_status = 1 and  order.status =0 and refund_status=0 THEN price_real ELSE 0 END), 0) AS pay_total";
        switch ($type) {
            case 1:
                $sql .= ",HOUR(FROM_UNIXTIME(order.created_at)) as _hour";
                break;
            default:
                $sql .= ", DATE_FORMAT( FROM_UNIXTIME(order.created_at ), '%m-%d' ) as _hour";
                break;
        }
        $orderList = DB::table('order')->selectRaw($sql)->leftJoin('dragon', 'dragon.id', '=', 'order.dragon_id')
            ->where('order.created_at', '>=', $startTime)->where('order.created_at', '<=', $endTime)->where('dragon.user_id', $userId)
            ->groupBy("_hour")->get()->toArray();
        return self::completeOrderSaleData($orderList, $type, $days);
    }

    protected static function completeOrderSaleData($orderList, $type, $days)
    {
        $array = $categories = [];
        if (empty($orderList)) {
            $newArray = [];
        } else {
            foreach ($orderList as $item) {
//                $newArray['x_' . $item->_hour] = ['order_num' => $item->order_num, 'pay_total' => $item->pay_total];
                $newArray['x_' . $item->_hour] = ['pay_total' => $item->pay_total];
            }
        }
        switch ($type) {
            case 1:
                for ($i = 0; $i < 24; $i++) {
                    $categories[] = $i;
                    $key          = 'x_' . $i;
                    if (!empty($newArray) && !empty($newArray[$key])) {
//                        $array['order_num'][] = (int)$newArray[$key]['order_num'];
                        $array['pay_total'][] = Helper::centToYuan($newArray[$key]['pay_total']);
                    } else {
//                        $array['order_num'][] = 0;
                        $array['pay_total'][] = Helper::centToYuan(0);
                    }

                }
                break;
            default:
                for ($i = $days-1; $i >= 0; $i--) {
                    $str          = strtotime("- $i days");
                    $key          = date('m-d', $str);
                    $categories[] = $key;
                    $arrayKey     = 'x_' . $key;
                    if (!empty($newArray) && !empty($newArray[$arrayKey])) {
//                        $array['order_num'][] = (int)$newArray[$arrayKey]['order_num'];
                        $array['pay_total'][] = Helper::centToYuan($newArray[$arrayKey]['pay_total']);
                    } else {
//                        $array['order_num'][] = 0;
                        $array['pay_total'][] = Helper::centToYuan(0);
                    }
                }
                break;
        }
        $series = [
//            ['name' => '订单数量', 'data' => $array['order_num']],
//            ['name' => '总金额', 'data' => $array['pay_total'], 'pointShape' => 'none', 'format' => 'yAxisDemo4']
            ['name' => '总金额', 'data' => $array['pay_total'], 'pointShape' => 'none']
        ];
        return compact("categories", "series");
    }

    public function dragStatics(UserContext $userContext)
    {
        $userId        = $userContext->getId();
        $dragonId      = request('dragon_id') ?? 0;
        $condition     = [
            'dragon_id'  => $dragonId,
            'pay_status' => 1
        ];
        $sql           = "SUM(CASE WHEN user_id = $userId  THEN 1 ELSE 0 END) AS wcyd,
               SUM(CASE WHEN verify = 1 and status =0 and refund_status=0  THEN 1 ELSE 0 END) AS dhx,
               SUM(CASE WHEN status = 0  THEN 1 ELSE 0 END) AS jllb";
        $statics       = DB::table('order')->where($condition)->selectRaw($sql)->first();
        $statics->wcyd = $statics->wcyd ?? 0;
        $statics->dhx  = $statics->dhx ?? 0;
        $statics->jllb = $statics->jllb ?? 0;
        return $statics;
    }

    public static function dealGoods($list)
    {
        if (empty($list)) {
            return $list;
        }
        $arr = [];
        foreach ($list as $item) {
            if ($item['num'] > 0) {
                unset($item['created_at']);
                unset($item['updated_at']);
                $arr[] = $item;
            }
        }
        return $arr;
    }

}
